﻿// The author disclaims copyright to this source code.
using System;
using System.Collections.Generic;
using System.Text;

namespace RyijyApp
{
    /// <summary>
    /// CRC32 calculation algorithm according to Sample code referenced in PNG 1.2 online specification.
    /// http://www.libpng.org/pub/png/spec/1.2/PNG-CRCAppendix.html
    /// </summary>
    class Crc32
    {
        uint[] table = new uint[256];
        public Crc32()
        {
            uint crc = 0;
            for (uint i = 0; i < 256; i++)
            {
                crc = i;
                for (uint j = 0; j < 8; j++)
                {
                    if ((crc & 1) != 0)
                        crc = 0xedb88320 ^ (crc >> 1);
                    else crc = crc >> 1;
                }
                table[i] = crc;
            }
        }
        /// <summary>
        /// Calculates CRC32 for the data buffer.
        /// </summary>
        /// <param name="data">Data buffer</param>
        /// <param name="offset">Offset in databuffer where crc calculation begins.</param>
        /// <param name="length">Length of data for which crc is calculated.</param>
        /// <returns></returns>
        public uint Process(byte[] data, int offset, int length)
        {
            return Process_crc(0xffffffff, data, offset, length) ^0xffffffff;
        }
        uint Process_crc(uint crc, byte[] data, int offset, int length)
        {
            if (length == -1)
                length = data.Length - offset;
            for (int i = offset; i < length; i++)
            {
                crc = (crc >> 8) ^ table[(crc ^ data[i]) & 0xff];
            }

            return crc;
        }
        /// <summary>
        /// Inserts CRC32 to end of the buffer.
        /// </summary>
        /// <param name="data">Data buffer</param>
        /// <param name="startingOffset">crc calculation starting offset in data buffer.</param>
        public void InsertCrcToEnd(byte[] data, int startingOffset)
        {
            uint crc = Process(data, startingOffset, data.Length - 4 - startingOffset);
            data[data.Length - 4] = Convert.ToByte(0xff & (crc >> 24));
            data[data.Length - 3] = Convert.ToByte(0xff & (crc >> 16));
            data[data.Length - 2] = Convert.ToByte(0xff & (crc >> 8));
            data[data.Length - 1] = Convert.ToByte(0xff &  crc );
        }
    }
}